﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

// Reviewed
#pragma once

#include "GcmpAddin.h"
#include <vector>
#include "GcmpApiDeclaration.h"

namespace gcmp
{
    /// \brief 插件操作结果
    enum class AddinResult : int32_t
    {
        SUCCESSFUL_RETURN,      ///< 成功
        FAILURE_LOADED,         ///< 插件在已加载插件列表中
        FAILURE_NOTLOADED,      ///< 插件不在已加载插件列表中
        FAILURE_NOTEXIST,       ///< 插件不存在
        FAILURE_CAN_NOT_UNLOAD, ///< 插件不能被卸载，比如内建插件
        FAILURE_UNKNOWN,        ///< 未知原因
    };

    class IAddinEvent;

    /// \brief 插件管理器
    ///
    /// GCMP提供实现，不允许外部派生。
    FINAL_INTERFACE class GCMP_ADDIN_EXPORT IAddinManager
    {
    public:
        static IAddinManager * Get();

    public:
        /// \brief 加载指定的插件。
        /// \param addinId 插件配置文件中指定的插件Id。
        /// \return AddinResult 结果。
        virtual AddinResult LoadAddin(const std::wstring& addinId) = 0;

        /// \brief 反初始化所有插件。
        ///
        /// 在程序关闭的时候调用，调用还未卸载的所有插件的UninitializeAddin()方法
        virtual void UninitializeAllAddins() = 0;

        /// \brief 卸载指定的插件。
        /// \param[in] addinId 插件配置文件中指定的插件Id。
        /// \param[out] pErrorMessage 如果传入非空，插件无法卸载时返回报错信息。
        /// \return AddinResult 结果。
        virtual AddinResult UnLoadAddin(const std::wstring& addinId, std::wstring* pErrorMessage) = 0;

        /// \brief 获取所有的插件Id
        /// \return std::vector<std::wstring> 所有的插件Id
        virtual std::vector<std::wstring> GetAllAddinIds() const = 0;

        /// \brief 根据插件Id获取插件名字
        /// \param[in]  addinId 插件Id
        /// \param[out] addinName 插件名字
        /// \return bool 插件不存在返回false
        virtual bool GetAddinName(const std::wstring & addinId, std::wstring & addinName) const = 0;

        /// \brief 根据插件Id获取公司名称
        /// \param[in]  addinId 插件Id
        /// \param[out] company 公司名称
        /// \return bool 插件不存在返回false
        virtual bool GetAddinCompany(const std::wstring & addinId, std::wstring & company) const = 0;

        /// \brief 根据插件Id获取模块组Guid
        /// \param[in]  addinId 插件Id
        /// \param[out] moduleGroupGuid 模块组Guid
        /// \return bool 插件不存在返回false
        virtual bool GetAddinModuleGroupGuid(const std::wstring & addinId, Guid & moduleGroupGuid) const = 0;

        /// \brief 根据插件Id获取依赖项
        /// \param[in]  addinId 插件Id
        /// \param[out] dependenciesSet 依赖项
        /// \return bool 插件不存在返回false
        virtual bool GetAddinDependencies(const std::wstring & addinId, std::set<std::wstring>& dependenciesSet) const = 0;

        /// \brief 插件是否需要在启动时加载
        /// \param addinId 插件Id
        /// \return bool 需要在启动时加载返回true；不需要或者插件不存在返回false
        virtual bool DoesAddinNeedToBeLoadedAtStartUp(const std::wstring & addinId) const = 0;


        /// \brief 查询插件是否已经被加载
        /// \param addIn 插件Id
        /// \return bool 插件被加载返回true；没有被加载或者不存在返回false
        virtual bool IsAddinLoaded(const std::wstring & addinId) const = 0;

        /// \brief 查询插件是否内在的
        ///
        /// 内在模块启动时必须被加载，并且不能被卸载
        /// \param addinId 插件Id
        /// \return bool 插件为内在的返回true；插件不为内在的返回false
        virtual bool IsIntrinsic(const std::wstring& addinId) const = 0;

        /// \brief 查询是否存在该插件
        /// \param addinId 插件Id
        /// \return bool 插件存在返回true；插件不存在返回false
        virtual bool DoesAddinExist(const std::wstring& addinId) const = 0;

        /// \brief 获取内部插件配置目录
        ///
        /// \return 内部插件配置目录 如果没有调用过SetAddinConfigDirectory设置过插件配置文件目录，那么默认是plugin_config
        virtual std::wstring GetAddinConfigDirectory() const = 0;

        /// \brief 设置内部插件配置目录
        ///
        /// 内部插件配置目录是相对于可执行程序的相对路径
        /// \param directory 插件配置目录
        /// \return 目前始终返回true
        virtual bool SetAddinConfigDirectory(const std::wstring& directory) = 0;

        /// \brief 加载配置文件夹下所有插件
        /// \param configurationFolderName 配置文件夹
        /// \return 加载结果
        virtual AddinResult LoadAddins(const std::wstring& configurationFolderName) = 0;

        /// \brief 获取外部插件配置目录
        ///
        /// \return 外部插件配置目录
        virtual std::set<std::wstring> GetExternalAddinConfigDirectories() const = 0;

        /// \brief 增加外部插件配置目录
        ///
        /// 外部插件配置目录为绝对路径
        /// \param directories 外部插件配置目录
        /// \return 目前始终返回true
        virtual bool AddExternalAddinConfigDirectory(const std::set<std::wstring>& directories) = 0;

        /// \brief 加载配置的外部插件文件夹下所有插件
        /// \param externalAddinsFolderPaths 配置的外部插件文件夹路径
        /// \return 加载结果
        virtual AddinResult LoadAddins(const std::set<std::wstring>& externalAddinsFolderPaths) = 0;

        /// \brief 获取插件事件
        /// \return 插件事件
        virtual IAddinEvent * GetAddinEvent() = 0;

        /// \brief 根据插件Id获取插件的绝对路径
        /// \param[in]  addinId 插件Id
        /// \param[out] fullPath 绝对路径
        /// \return bool 插件不存在返回false
        virtual bool GetAddinFullPath(const std::wstring & addinId, std::wstring & fullPath) const = 0;

        /// \brief 根据插件Id获取插件相对exe位置
        /// \param[in]  addinId 插件Id
        /// \param[out] relativePath 相对路径
        /// \return bool 插件不存在返回false
        GCMP_OBSOLETE_API(2021 / 12 / 01, IAddinManager::GetAddinFullPath((const std::wstring&, std::wstring&) const)) virtual bool GetAddinRelativePath(const std::wstring & addinId, std::wstring & relativePath) const = 0;

        /// \brief 根据插件Id获取插件的模块句柄
        /// \param[in]  addinId 插件Id
        /// \return HINSTANCE 插件的模块句柄,没有加载则为空
        GCMP_DEPRECATED_API(2022 / 10 / 01) virtual HINSTANCE GetAddinHandle(const std::wstring& addinId) const = 0;

    public:
        virtual ~IAddinManager() = 0;
    };
}
